﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using CustomConsole;
using System.Diagnostics;
using System.Threading;
using System.Windows.Threading;
using WpfConsole.Properties;
using System.Collections.ObjectModel;

namespace WpfConsole
{
    /// <summary>
    /// Window1.xaml の相互作用ロジック
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
            ConsoleVW.ConsoleClose += ConsoleClose;

            CommandBooker booker = new CommandBooker(ConsoleVW);
            ((TabItem)TabCtrl.Items[0]).Tag = booker;
        }

        private void ConsoleClose(ConsoleView view)
        {
            if (TabCtrl.Items.Count == 1)
            {
                Application.Current.Shutdown();
                return;
            }

            var target = (from TabItem item in TabCtrl.Items
                         where item.Content == view
                         select item).FirstOrDefault();

            if (target != null)
            {
                RemoveTab(target);
            }
        }

        private void RemoveTab(TabItem item)
        {
            ConsoleView view = (ConsoleView)item.Content;
            TabCtrl.Items.Remove(item);

            new Thread(() => view.Dispose()); // why stacked?
        }

        private void TabCtrl_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if(e.AddedItems.Count != 0)
            {
                TabItem item = (TabItem)e.AddedItems[0];
                ConsoleView console = item.Content as ConsoleView;
                if (console != null)
                {
                    console.Active = true;
                    CommandBooker booker = (CommandBooker)item.Tag;
                    BookCommandCB.ItemsSource = booker.Commands;
                }
            }
            if (e.RemovedItems.Count != 0)
            {
                TabItem item = (TabItem)e.RemovedItems[0];
                ConsoleView console = item.Content as ConsoleView;
                if (console != null)
                {
                    console.Active = false;
                }
            }
        }

        private void NewTabBtn_Click(object sender, RoutedEventArgs e)
        {
            ConsoleView control = new ConsoleView();
            control.ConsoleClose += ConsoleClose;
            control.Active = false;
            string cmdName = CreateCmdName();
            TabItem item = new TabItem() { Header = cmdName, Tag = control };
            item.Content = control;
            item.Tag = new CommandBooker(control);
            TabCtrl.Items.Add(item);

            TabCtrl.SelectedItem = item;
        }

        private string CreateCmdName()
        {
            int i = 1;
            string titleCandidate;
            do
            {
                titleCandidate = String.Format("cons({0})", i++);
            } while (TitleExist(titleCandidate));

            return titleCandidate;
        }

        private bool TitleExist(string titleCandidate)
        {
            var matched = from TabItem item in TabCtrl.Items
                          where item.Header.ToString() == titleCandidate
                          select item;
            return matched.Count() != 0;
        }

        private void CloseBtn_Click(object sender, RoutedEventArgs e)
        {
            if (TabCtrl.Items.Count > 1)
            {
                RemoveTab((TabItem)TabCtrl.SelectedItem);
            }
        }

        private void DeleteHistory_Click(object sender, RoutedEventArgs e)
        {
            var delTarget = from ComboBoxItem item in BookCommandCB.ItemsSource
                            where item.IsHighlighted
                            select item;

            List<ComboBoxItem> delTargetList = new List<ComboBoxItem>(delTarget);
            delTargetList.ForEach(i => ((ObservableCollection<ComboBoxItem>)BookCommandCB.ItemsSource).Remove(i));
        }

        private void BookCommandCB_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                string command = BookCommandCB.Text;
                if (!String.IsNullOrEmpty(command))
                {
                    CommandBooker booker = (CommandBooker)((TabItem)TabCtrl.SelectedItem).Tag;

                    ComboBoxItem item = new ComboBoxItem();
                    item.Content = command;
                    booker.Commands.Add(item);
                    BookCommandCB.Text = String.Empty;
                }
            }
        }

        private void StartTimerIfNecesary()
        {
            if (!NeedStartWatchDog)
                return;

            StartWatchDog();
        }

        private DateTime _watchStart;

        private DispatcherTimer _timer = new DispatcherTimer();

        private void StartWatchDog()
        {
            StartBtnIsEnabled = false;

            _watchStart = DateTime.Now;
            _timer.Stop();

            TimeSpan span = new TimeSpan(0, 0, Settings.Default.WatchDogInterval);
            _timer.Interval = span;
            _timer.Tick += new EventHandler(timer_Tick);
            _timer.Start();
        }

        private IEnumerable<CommandBooker> Bookers
        {
            get
            {
                return from TabItem item in TabCtrl.Items
                       select (CommandBooker)item.Tag;
            }
        }

        int WatchDogInterval
        {
            get
            {
                int val;
                if (!Int32.TryParse(WatchDogIntervalCB.Text, out val))
                    throw new FormatException();
                return val;
            }
        }

        bool NeedStartWatchDog
        {
            get
            {
                try
                {
                    int val = WatchDogInterval;
                }
                catch (FormatException)
                {
                    return false;
                }

                var activeBookers = from booker in Bookers
                                    where booker.Commands.Count > 0
                                    select booker;
                return (activeBookers.Count() > 0);
            }
        }


        void timer_Tick(object sender, EventArgs e)
        {
            try
            {
                int val = WatchDogInterval;
                var fireableBooker = from booker in Bookers
                                     //for debug where (DateTime.Now - booker.LastChange).TotalMinutes > val &&
                                     where (DateTime.Now - booker.LastChange).TotalSeconds > val &&
                                           booker.Commands.Count > 0
                                     select booker;

                fireableBooker.ToList().ForEach(b => b.FireFirstCommand());
            }
            catch (FormatException)
            {
                _timer.Stop();
                StartBtnIsEnabled = true;
                return;
            }

            if (NeedStartWatchDog)
                return;

            _timer.Stop();
            StartBtnIsEnabled = true;
        }

        private bool StartBtnIsEnabled
        {
            set
            {
                StartBtn.IsEnabled = value;
                StopBtn.IsEnabled = !value;
            }
        }

        private void WatchStart_Click(object sender, RoutedEventArgs e)
        {
            StartTimerIfNecesary();
        }

        private void WatchStop_Click(object sender, RoutedEventArgs e)
        {
            StartBtnIsEnabled = true;
            _timer.Stop();
        }

    }
}
